package com.bright.ghj.user.config;

import com.bright.ghj.common.util.StringUtil;
import com.bright.ghj.user.cas.CasAuthenticationEntryPointImpl;
import com.bright.ghj.user.cas.CasServiceAuthenticationDetailsSource;
import com.bright.ghj.user.handler.CasAuthenticationSuccessHandler;
import com.bright.ghj.user.handler.LogoutRemoveUserHandler;
import com.bright.ghj.user.properties.CasProperties;
import com.bright.ghj.user.security.Cas20ProxyTicketValidatorExt;
import com.bright.ghj.user.security.CasAuthenticationProviderExt;
import com.bright.ghj.user.security.OnlineUserFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy;

import java.util.List;

/**
 * @Author txf, hxj
 * @Date 2022/6/24 15:42
 * @Description
 */
//@Configuration
public abstract class AbstractWebSecurityCasConfig extends WebSecurityConfigurerAdapter {

//    @Autowired
    protected CasProperties casProperties;
//    @Autowired
    protected CasAuthenticationEntryPointImpl casAuthenticationEntryPoint;
//    @Autowired
    protected AuthenticationUserDetailsService<CasAssertionAuthenticationToken> casUserDetailsService;

//    @Override
    protected void configureHttpSecurity(HttpSecurity http, List<String> getPermitAllPatterns, CasAuthenticationFilter casAuthenticationFilter,
                                         OnlineUserFilter onlineUserFilter, LogoutFilter casLogoutFilter, SingleSignOutFilter singleSignOutFilter) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry requests = http.authorizeRequests();//配置安全策略
        // 遍历所有permitAll网址
        for (String pattern : getPermitAllPatterns) {
            requests.antMatchers(pattern).permitAll();
        }
                //.antMatchers("/doc.html").permitAll()
//                .antMatchers("/login", "/send").permitAll()
//                .antMatchers("/static/**").permitAll()
//                .antMatchers("/**").permitAll()

        requests.anyRequest().authenticated() //所有请求都要验证
                .and()
                .csrf().disable()
                .logout().permitAll() //logout不需要验证
                .and()
                .headers().frameOptions().disable()
                .and()
                .cors()
                .and().formLogin(); //使用form表单登录

        http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint)
                .and()
                .addFilter(casAuthenticationFilter)
                .addFilterAfter(onlineUserFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(casLogoutFilter, LogoutFilter.class)
                .addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class);
    }


//    @Override
    protected void configureAuth(AuthenticationManagerBuilder auth, CasAuthenticationProvider casAuthenticationProvider) throws Exception {
        super.configure(auth);
        auth.authenticationProvider(casAuthenticationProvider);
    }

    @Bean
    public ServiceProperties serviceProperties() {
        ServiceProperties serviceProperties = new ServiceProperties();
        serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
        serviceProperties.setSendRenew(false);
        serviceProperties.setAuthenticateAllArtifacts(true);
        return serviceProperties;
    }

    @Bean
    public CasAuthenticationFilter casAuthenticationFilter(ServiceProperties serviceProperties, SessionAuthenticationStrategy sessionAuthenticationStrategy) throws Exception {
        CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
        casAuthenticationFilter.setServiceProperties(serviceProperties);
        casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
        casAuthenticationFilter.setAuthenticationManager(authenticationManager());
//        casAuthenticationFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler(casProperties.getAppHomeUrl()));
        // 20251118 兼容多域名登录
        casAuthenticationFilter.setAuthenticationDetailsSource(new CasServiceAuthenticationDetailsSource(casProperties));
        casAuthenticationFilter.setAuthenticationSuccessHandler(new CasAuthenticationSuccessHandler(casProperties.getAppHomeUrl()));
        casAuthenticationFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
        return casAuthenticationFilter;
    }

    @Bean
    public CasAuthenticationProviderExt casAuthenticationProvider(ServiceProperties serviceProperties, Cas20ProxyTicketValidatorExt cas20ServiceTicketValidator) {
        CasAuthenticationProviderExt casAuthenticationProvider = new CasAuthenticationProviderExt();
        casAuthenticationProvider.setServiceProperties(serviceProperties);
        casAuthenticationProvider.setTicketValidatorExt(cas20ServiceTicketValidator);
        casAuthenticationProvider.setAuthenticationUserDetailsService(casUserDetailsService);
        casAuthenticationProvider.setKey("casAuthenticationProviderKey");
        return casAuthenticationProvider;
    }

    @Bean
    public Cas20ProxyTicketValidatorExt cas20ServiceTicketValidator() {
        // 如果有配置内网地址则用内网地址登录 无则使用外网地址
        String casServerUrl = StringUtil.isEmpty(casProperties.getCasServerInnerHost()) ? casProperties.getCasServerUrl().get(0) : casProperties.getCasServerInnerHost();
        Cas20ProxyTicketValidatorExt cas20ServiceTicketValidator = new Cas20ProxyTicketValidatorExt(casServerUrl);
        cas20ServiceTicketValidator.setEncoding("UTF-8");
        return cas20ServiceTicketValidator;
    }

    @Bean
    public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new SessionFixationProtectionStrategy();
    }

    @Bean
    public SingleSignOutFilter singleSignOutFilter() {
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
        singleSignOutFilter.setIgnoreInitConfiguration(true);
        return singleSignOutFilter;
    }

    @Bean
    public LogoutFilter casLogoutFilter() {
        LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(),
                new SecurityContextLogoutHandler());
        logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());
        return logoutFilter;
    }

    @Bean
    public OnlineUserFilter onlineUserFilter() {
        return new OnlineUserFilter(casProperties);
    }

    @Bean
    public LogoutRemoveUserHandler logoutRemoveUserHandler() {
        return new LogoutRemoveUserHandler();
    }


    @Bean
    public GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults("");
    }

}
